package base.juc;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 * 安全集合的使用场景
 *
 * 防治每个用户 规定时间内 不要重复请求接口
 * 通过ConcurrentHashMap 解决缓存的
 *
 * Author: shen qi han
 * Date: 2022/4/6 上午12:41
 */
public class ConcurrentHashMapMain {

    /**
     * 一小时
     */
    static int num = 100;
    private static long timeLimit = 3600*1000;
    private static int visitLimit = 10000;
//    private static Map<Integer, LimitEntity> cacheMap = new ConcurrentHashMap<>();
    private static Map<Integer, LimitEntity> cacheMap = new HashMap<>();
    private static CountDownLatch cdl = new CountDownLatch(num);


    /**
     * 限制类 对象
     */
    static class LimitEntity{
        Long beginTime = 0L;
        int times = 0;
        public Long getBeginTime() {return beginTime;}
        public void setBeginTime(long beginTime) {this.beginTime = beginTime;}
        public int getTimes() {return times;}
        public void setTimes(int times) {this.times = times;}
    }

    public static void count(int userId, long now){
        // 读操作
        LimitEntity limit = cacheMap.get(userId);
        int times = 1;
        if(limit == null){
            // 首次访问
            limit = new LimitEntity();
            limit.setBeginTime(now);
            limit.setTimes(times);
            // 写操作
            cacheMap.put(userId, limit);
        }else{
            long beginTime = limit.getBeginTime();
            // 超出一个小时
            if(now - beginTime > timeLimit){
                limit.setBeginTime(now);
                limit.setTimes(times);
                // 写操作
                cacheMap.put(userId, limit);
            }else{
                times = limit.getTimes() + 1;
                if(times > visitLimit){
                    System.out.println("超出访问限制.");
                    return;
                }else{
                    // 没有超出，更新次数
                    limit.setTimes(times);
                    cacheMap.put(userId, limit);
                }
            }
        }
//        System.out.println("userId: " + userId + "; now - beginTimes: " + (now - limit.getBeginTime()) + "; times: " + limit.getTimes());
    }

    /**
     * 模拟多线程 请求接口
     */
    static class MyTask implements Runnable{
        int userId = 0;
        public MyTask(int userId){this.userId = userId;}
        @Override
        public void run() {
            int times = 20;
            for(int i = 0; i < times; i++){
                count(userId, Calendar.getInstance().getTimeInMillis());
            }
            // 控制线程
            cdl.countDown();
        }
    }


    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(num);
        for(int i = 0; i < num; i++){
            MyTask task = new MyTask(i);
            pool.submit(task);
        }
        cdl.await();
        pool.shutdown();
        System.out.println("finish.");
    }

}
